/* eslint-disable */
import { loadModules } from 'esri-loader'
import Rbush from '../domLayer/rbush'
class DomLayerView2D {
  async init() {
    const [geometryEngine, LayerView] = await loadModules([
      'esri/geometry/geometryEngine',
      'esri/views/2d/layers/BaseLayerView2D',
    ])
    var clazz = LayerView.createSubclass({
      transformOffset: {
        x: 0,
        y: 0,
      },
      constructor(param) {
        param.layer.on(
          'change',
          function ({ added, removed }) {
            removed.forEach((v) => {
              this._remove(v)
            })
            added.forEach((v) => {
              this._add(v)
            })
            this.render()
          }.bind(this)
        )
        param.layer.on(
          'render',
          function () {
            this.render()
          }.bind(this)
        )
      },
      _add: function (ele) {
        var initStyle = { position: 'absolute', willChange: 'transform', top: 0, left: 0 }
        if (ele.node && ele.node.parentNode === this._displayDiv) {
          //todo
        } else {
          if (typeof ele.dom === 'string') {
            ele.node = document.createElement('div')
            ele.node.innerHTML = ele.dom
            this._setStyle(ele.node, initStyle)
            this._displayDiv.append(ele.node)
          } else {
            ele.node = document.createElement('div')
            this._setStyle(ele.node, initStyle)
            ele.node.append(ele.dom)
            this._displayDiv.append(ele.node)
          }
        }
      },
      _remove(ele) {
        if (ele.node) {
          ele.node.remove()
        }
      },
      setIndex() {
        const index = this.view.map.layers.findIndex((v) => v === this.layer)
        if (this._displayDiv)
          this._setStyle(this._displayDiv, {
            'z-index': index,
          })
      },
      attach() {
        var surface = this.view.overlay.surface
        this.divLayerClass = 'div-layer'
        var display = this.layer.visible ? 'block' : 'none'
        const _displayDiv = document.getElementById(this.layer.id)
        if (_displayDiv) surface.removeChild(_displayDiv)
        this._displayDiv = document.createElement('div')
        this._displayDiv.id = this.layer.id
        this._displayDiv.classList.add(this.divLayerClass)
        this._setStyle(this._displayDiv, {
          width: '100%',
          height: '100%',
          position: 'absolute',
          top: '0px',
          right: '0px',
          left: '0px',
          bottom: '0px',
          display: display,
        })
        this.setIndex()
        surface.append(this._displayDiv)
        this.layer.graphics.forEach((v) => {
          if (!v.node) this._add(v)
        })
      },
      render() {
        this.setIndex()
        var rbush = new Rbush()
        this.layer.graphics.forEach((v, i) => {
          if (v.node) {
            if (this.isInExtent(v) && v.visible !== false) {
              const pos = this.view.toScreen(v.geometry)
              const width = v.node.clientWidth
              const height = v.node.clientHeight
              let x, y
              switch (this.layer.placement) {
                case 'left-bottom':
                  y = pos.y - height
                  x = pos.x
                  break
                default:
                  x = pos.x - width / 2
                  y = pos.y - height
                  break
              }
              const box = {
                minX: parseInt(x),
                minY: parseInt(y),
                maxX: parseInt(x) + parseInt(width),
                maxY: parseInt(y) + parseInt(height),
              }
              this._setStyle(v.node, {
                transform: `translate(${x}px,${y}px)`,
                'z-index': this.layer.graphics.length - i,
              })
              var find = rbush.search(box)
              if (find.length) {
                v.node.style.visibility = 'hidden'
                v.node.style.pointerEvents = 'none'
              } else {
                v.node.style.visibility = 'visible'
                v.node.style.pointerEvents = 'all'
                rbush.insert(box)
              }
            } else {
              v.node.style.visibility = 'hidden'
              v.node.style.pointerEvents = 'none'
            }
          }
        })
      },
      _setStyle(dom, obj) {
        for (const key in obj) {
          dom.style[key] = obj[key]
        }
      },

      isInExtent: function (ele) {
        return geometryEngine.contains(this.view.extent, ele.geometry)
      },
      detach() {
        this.destroy()
      },
      destroy() {
        var surface = this.view.overlay.surface
        if (this._displayDiv) surface.removeChild(this._displayDiv)
      },
    })

    return clazz
  }
}
export default new DomLayerView2D()
